﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using Com.SuperCache.Engine;

namespace Com.SuperCache.Test
{
    public class Foo
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public double? Some { get; set; }
        public DateTime? Birthday { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //TestAddGet();

            //Thread.Sleep(6000);
            //TestExpiration();

            TestDefaultDiskPerformance();
            //TestDefaultMemoryPerformance();
            //TestRawDiskPerformance();
            //TestRawMemoryPerformance();

            //TestConcurrent();

            Console.Read();
        }

        private static void TestConcurrent()
        {
            var w = new Stopwatch();
            w.Start();
            Parallel.For(1, 3, (a) =>
            {
                var employees = Enumerable.Range((a - 1) * 1000, a * 1000).Select(i => new KeyValuePair<int, string>(i, "Wilson " + i + " Chen"));
                var engine = new CacheEngine(@"..\..\data");
                engine.Add<int, string>("Employee", employees, DateTime.Now.AddMinutes(1));
            });
            w.Stop();
            Console.WriteLine("add:" + w.Elapsed);

            var engine2 = new CacheEngine(@"..\..\data");
            var o = engine2.Get<int, string>("Employee", 1005);
            Console.WriteLine(o);
        }

        private static void TestDefaultDiskPerformance()
        {
            TestPerformance(CacheProviders.Default, @"..\..\data");
        }

        private static void TestDefaultMemoryPerformance()
        {
            TestPerformance(CacheProviders.Default, string.Empty);
        }

        private static void TestRawDiskPerformance()
        {
            TestPerformance(CacheProviders.Raw, @"..\..\data");
        }

        private static void TestRawMemoryPerformance()
        {
            TestPerformance(CacheProviders.Raw, string.Empty);
        }

        private static void TestPerformance(CacheProviders Provider, string DataPath)
        {
            Console.WriteLine("Performance Test: " + Provider.ToString() + ", " + (string.IsNullOrEmpty(DataPath) ? "Memory" : DataPath));
            var engine = new CacheEngine(Provider, DataPath, RecycleAlgorithms.MRU, 900, 100, RecycleModes.Passive);
            var w = new Stopwatch();

            w.Start();
            var employees = Enumerable.Range(0, 1000).Select(i => new KeyValuePair<int, string>(i, "Wilson " + i + " Chen"));
            engine.Add<int, string>("Employee", employees, DateTime.Now.AddMinutes(1));
            w.Stop();
            Console.WriteLine("add:" + w.Elapsed);

            /*w.Restart();
            employees.ForEach(key =>
                {
                    var o1 = engine.Get<int, string>("Employee", key.Key);
                });
            w.Stop();
            Console.WriteLine("individual get:" + w.Elapsed);*/

            w.Restart();
            var keys = employees.Select(i => i.Key);
            var o = engine.Get<int, string>("Employee", keys);
            Console.WriteLine("first key:{0},first value{1}", o.First().Key, o.First().Value);
            w.Stop();
            Console.WriteLine("get:" + w.Elapsed);
            Console.WriteLine();
        }

        private static void TestExpiration()
        {
            var engine = new CacheEngine(@"..\..\data");
            var o = engine.Get<string, Foo>("User", "wchen");
            Console.WriteLine(o != null ? o.Name : "wchen does not exist or expired");
        }

        private static void TestAddGet()
        {
            var engine = new CacheEngine(@"..\..\data");
            var f = new Foo { Name = "Wilson Chen", Age = 30, Birthday = DateTime.Now, Some = 123.456 };
            engine.Add("User", "wchen", f, DateTime.Now.AddSeconds(5));

            var o = engine.Get<string, Foo>("User", "wchen");
            Console.WriteLine(o.Name);

            var o4 = engine.Get<string, Foo>("User", "foo");
            Console.WriteLine(o4 != null ? o4.Name : "foo does not exist");

            var o3 = engine.Get<string, string>("PlainText", "A");
            Console.WriteLine(o3 ?? "A does not exist");
        }
    }
}